package openadmin.menu;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.ResourceBundle;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Class that Analyzes a XML Document. This clas can:
 * <ul>
 * <li>Parse a XML document and return a Node to it
 * <li>Remove nodes that have no leaves under it
 * <li>Gets a DefaultMutableTreeNode to be used by Swing from the XML Document
 * <li>Gets a TreeItem to be used by GWT from the XML Document
 * <li>Gets an independent Tree Format from the XML Document
 * </ul>
 * <p>
 * @author edu
 * @date 15/04/2009
 *
 */
public class XMLAnalyzer {
	
	
	/**
	 * <desc> Parses a XML document and obtains a Node with the structure of the XML document 
	 * <pre>  Initially we have an XML file
	 * <post> We get an org.w3c.dom.Node with the XML structure.
	 * <p>
	 * @param pXMLFile The XML file to parse
	 * @return a Node 
	 */
	public static Node analyzeXML(String pXMLFile)  {
	
		// obtains xml parser	     
		Node rootNode =null;
		try {
		
			// Creates factory builder
			DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbFactory.newDocumentBuilder();

			// parses xml input file obtaining doc object
			Document doc;
			doc = db.parse(new File(pXMLFile));

			// analyzes elements
			rootNode = doc.getDocumentElement();		    		    			  


		} catch (SAXException e) {
			e.printStackTrace();

		} catch (IOException e) {
			e.printStackTrace();

		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}

		return rootNode;
	}
	
    /**
     * <desc> If a node has no leaves and its children have no leaves, then it is removed
	 * <pre>  Initially we have an org.w3c.dom.Node
	 * <post> The nodes with no leaves under then are removed
	 * <p>
     * @param myNode the node to search for leaves and 
     */
	public static void removeNoLeafNodes(Node myNode, HashMap<String,NodeV2> hMapNode ) {
    	
    	// Create a new node that has information about having leaves
		NodeV2 nV2=new NodeV2(myNode);
    	
		// Store this node in a hashMap
		if (hMapNode==null) hMapNode=new HashMap<String,NodeV2>();
    	hMapNode.put(Integer.toString(myNode.hashCode()),nV2);
    	//System.out.println("Analyzing :"+myNode.getNodeName()+ " " + myNode.getAttributes().getNamedItem("keyi18n").getNodeValue());
    	
    	// For every child in the collection
    	NodeList childNodes=myNode.getChildNodes();
		for (int i=0; i<childNodes.getLength();i++) {
			
			// Get the node
			Node n=childNodes.item(i);
			
			if (n.getNodeType() == Node.ELEMENT_NODE) {
				
				// Get the name of the node
				String name=n.getNodeName();
								
				// If program or folder
				if (name.equalsIgnoreCase("nodeProgram") || name.equalsIgnoreCase("nodeFolder")) {
					removeNoLeafNodes(n, hMapNode);
							
				// if leaf
				}else if ((name.equalsIgnoreCase("leafAction") || name.equalsIgnoreCase("leafClass")) && (!nV2.hasLeaves)){  
					nV2.hasLeaves=true;
				}
			}
		}	
		// if exists parent node
		Node parent=myNode.getParentNode();
		if (parent!=null) { 
			if (parent.getNodeType() == Node.ELEMENT_NODE) {
				
				// Makes true parent hasLeaves value
				if (nV2.hasLeaves) {
					NodeV2 nV2Parent=hMapNode.get(Integer.toString(parent.hashCode()));
					nV2Parent.hasLeaves=true;
				
				// Remove this node  from parent's node (because this node has no leaves)	
				}else {
					System.out.println("Removed Node:"+myNode.getNodeName()+ " " + myNode.getAttributes().getNamedItem("keyi18n").getNodeValue());
					parent.removeChild(myNode);
				}	
			}
		}
	} 
	
	/**
	 *  
	 * <desc> Parses a XML document and obtains a DefaultMutableTreeNode with translation with the structure of the XML document 
	 * <pre>  Initially we have an XML file
	 * <post> We get a DefaultMutableTreeNode with the XML structure.
	 * <p>
	 * @param pXMLFile the XML file to parse
	 * @param language the language to translate
	 * @param pRemoveNoLeafNodes if we want to delete nodes without leaves under them.
	 * @param rscBundle the resource bundle to use
	 * @return
	 */
	public static DefaultMutableTreeNode getDefaultMutableTreeNode(String pXMLFile, boolean pRemoveNoLeafNodes, String planguage, ResourceBundle pRscBundle){
		
		Node rootNode=analyzeXML(pXMLFile);
		
		// remove nodes with no leaves
		if (pRemoveNoLeafNodes) removeNoLeafNodes(rootNode, null);
		
		DefaultMutableTreeNode myNode = new DefaultMutableTreeNode(rootNode.getAttributes().getNamedItem("keyi18n").getNodeValue());
		// TODO: add attributes to the root node
		
		addChildNodes(myNode, rootNode.getChildNodes());
		
		return myNode;


	}
	
	
	/**
	 * Adds the children nodes to the parent
	 * 
	 * @param myNode the parent DefaultMutableTreeNode 
	 * @param childNodes the NodeList to add to the parent
	 */
	private static void addChildNodes(DefaultMutableTreeNode myNode, NodeList childNodes){
		
		// For every child in the collection
		for (int i=0; i<childNodes.getLength();i++) {
			
			// Get the node
			Node n=childNodes.item(i);
			
			if (n.getNodeType() == Node.ELEMENT_NODE) {
				
				// Get the name of the node
				String name=n.getNodeName();
				
				// Assign the child to a DefaultMutableTreeNode 
				DefaultMutableTreeNode childNode= new DefaultMutableTreeNode(n.getAttributes().getNamedItem("keyi18n").getNodeValue());
				myNode.add(childNode);
				
				// If program 
				if (name.equalsIgnoreCase("nodeProgram")){
					addChildNodes(childNode,n.getChildNodes()); 
					// TODO: add attributes to the program
				
				// if folder
				}else if (name.equalsIgnoreCase("nodeFolder")){
					addChildNodes(childNode,n.getChildNodes()); 
					// TODO: add attributes to the folder
					
				// if leaf
				}else if (name.equalsIgnoreCase("leafAction")){
					// TODO: add attributes to the leaf
				}
			}
				
			
		}
	}


}
